/*
 * $Id: JawsAuthorizingRealm.java 16 2014-08-22 10:12:14Z ratking $
 *
 * Copyleft (C) 2014 RatKing. All wrongs reserved.
 */
package cn.ratking.demo.jaws7.security.realm;

import java.util.Collection;

import javax.enterprise.inject.spi.CDI;

import org.apache.shiro.authc.AuthenticationException;
import org.apache.shiro.authc.AuthenticationInfo;
import org.apache.shiro.authc.AuthenticationToken;
import org.apache.shiro.authc.SimpleAuthenticationInfo;
import org.apache.shiro.authc.UsernamePasswordToken;
import org.apache.shiro.authz.AuthorizationException;
import org.apache.shiro.authz.AuthorizationInfo;
import org.apache.shiro.authz.SimpleAuthorizationInfo;
import org.apache.shiro.realm.AuthorizingRealm;
import org.apache.shiro.subject.PrincipalCollection;
import org.apache.shiro.util.ByteSource;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import cn.ratking.demo.jaws7.model.User;
import cn.ratking.demo.jaws7.system.service.UserService;

/**
 * 本类为非受管bean，因此里面不能使用@Inject
 */
public class JawsAuthorizingRealm extends AuthorizingRealm {

    private transient Logger log = LoggerFactory.getLogger(JawsAuthorizingRealm.class);
    /** 用于获取用户信息及用户权限信息的业务接口 */
    private UserService userService;

    /**
     * 获取用户信息及用户权限信息的业务接口
     *
     * @return 用户服务
     */
    public UserService getUserService() {
        if (userService == null) {
            // Application components which cannot obtain a BeanManager reference via injection nor JNDI lookup can get the reference from the javax.enterprise.inject.spi.CDI class via a static method call:
            // BeanManager manager = CDI.current().getBeanManager();
            // The CDI class can be used directly to programmatically lookup CDI
            // beans as described in Section 4.10, "Obtaining a contextual instance
            // by programmatic lookup"
            userService = (UserService) CDI.current().select(UserService.class).get();
            //log.debug("Debug: JawsAuthorizingRealm.getUserService(), userService={}", userService);
        }
        return userService;
    }

    /**
     * 获取认证信息
     *
     * @param authcToken
     * @return 认证信息
     * @throws AuthenticationException
     */
    @Override
    protected AuthenticationInfo doGetAuthenticationInfo(AuthenticationToken authcToken) throws AuthenticationException {
        UsernamePasswordToken token = (UsernamePasswordToken) authcToken;
        // 通过表单接收的用户名
        String username = token.getUsername();

//        // Null username is invalid
//        if (username == null) {
//            throw new AccountException("空用户名");
//        }
        if (username != null && !"".equals(username)) {
            User user = getUserService().findByUsername(username);
            if (user != null) {
                log.debug("Debug: JawsAuthorizingRealm.doGetAuthenticationInfo(), user={}", user);
                Object principal = user.getUsername();
                Object hashedCredentials = user.getPassword() == null ? "" : user.getPassword();
                ByteSource credentialsSalt = ByteSource.Util.bytes(user.getSalt());
                String realName = user.getRealName();
                return new SimpleAuthenticationInfo(principal, hashedCredentials, credentialsSalt, realName);
            }
        }

        return null;
    }

    /**
     * 获取授权信息
     *
     * @param principals
     * @return 授权信息
     */
    @Override
    protected AuthorizationInfo doGetAuthorizationInfo(PrincipalCollection principals) {
        //null usernames are invalid
        if (principals == null) {
            throw new AuthorizationException("PrincipalCollection为空");
        }

        String username = (String) principals.fromRealm(getName()).iterator().next();

        if (username != null) {
            // 查询用户授权信息
            SimpleAuthorizationInfo authorizationInfo = new SimpleAuthorizationInfo();
            Collection<String> roles = getUserService().queryRoles(username);
            authorizationInfo.addRoles(roles);
            Collection<String> permissions = getUserService().queryPermissions(username);
            authorizationInfo.addStringPermissions(permissions);
            log.debug("Debug: JawsAuthorizingRealm.doGetAuthorizationInfo(), authorizationInfo={}", authorizationInfo);
            return authorizationInfo;
        }

        return null;
    }
}
